﻿
// ———————————————————————–
// <copyright file="IdentificationTypeGenerator.cs" company="The MITRE Corporation">
//    Copyright (c) 2014 The MITRE Corporation. All rights reserved.
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// </copyright>
// ———————————————————————–
/////////////////////////////////////////////////////////////////////////////////////////////////
// FileNamePlaceholderGenerator.cs:
//
// A generator for good and bad examples of FileNamePlaceholder.
//
// Project: NIEMCADTest
// Author:  Lizzie DeYoung - MITRE
/////////////////////////////////////////////////////////////////////////////////////////////////

// Copyright (c) 2014 The MITRE Corporation. All rights reserved.
//
// NOTICE
// This software was produced for the U. S. Government
// under Contract No. FA8721-09-C-0001, and is
// subject to the Rights in Noncommercial Computer Software
// and Noncommercial Computer Software Documentation Clause
// (DFARS) 252.227-7014 (JUN 1995)  
      

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace NIEMCADTest.NIEMCoreTests
{
  public abstract class DateTimeRangeTypeGenerator : Generator
  {
    public const string START_DATETIME_SUB = "$start$";
    public const string END_DATETIME_SUB = "$end$";
    public const string CONTENT_SUB = "$content$";
    public const string INNER_NAME_SUB = "$innername$";
    public const string INNER_PREFIX_SUB = "$innerprefix$";
    public const string INNER_NAMESPACE_SUB = "$innernamespace$";

    public const string START_DATETIME = "StartDate";
    public const string END_DATETIME = "EndDate";
    public const string DATETIME = "DateTime";
    public const string NC_PREFIX = "nc";

    public const string DATETIME_TYPE = @"
    <$innerprefix$:$innername$ xmlns:$innerprefix$='$innernamespace$'>
      $content$
    </$innerprefix$:$innername$>";

    public const string DATETIMERANGE_TYPE = @"
    <$prefix$:$name$ xmlns:$prefix$='$namespace$'>
      $start$
      $end$
    </$prefix$:$name$>";

    public const string WRONG_ELEMENT_NAME = @"
    <$prefix$:asdf xmlns:$prefix$='$namespace$'>
      $start$
      $end$
    </$prefix$:asdf>";

    public static string[] GOOD_START_DATES =
      new string[3] { "2014-10-03T17:46:55.21Z", "2014-10-03T17:46:55.211234Z", "2014-10-03T17:46Z" };

    public static string[] GOOD_END_DATES =
      new string[3] { /* should be able to have same */ "2014-10-03T17:46:55.211234Z", 
        /* these occur later than the good start dates */ "2014-10-03T18:46:55.21Z", "2014-10-03T18:46Z" };

    public static string[] BAD_END_DATES =
      new string[3] { /* these occur earlier than the good start dates */
        "2014-10-03T16:46:55.21Z", "2014-10-03T16:46:55.211234Z", "2014-10-03T16:46Z" };

    //TODO: LDY should we be testing for the time zones? currently this doesn't happen. 
    // I kind of feel like we should do this, but i have some mixed feelings.
    /*
    public static string[] BAD_DATES =
      new string[3] { "2014-10-03T17:46:55.21", "2014-10-03T17:46:55.21+06:00", "asdf" };
     */
    public static string[] BAD_DATES =
      new string[1] { "asdf" };

    public List<TestObject> BAD_WrongElementName()
    {
      List<TestObject> list = new List<TestObject>();
      string xml = GetXml(WRONG_ELEMENT_NAME, 
        START_DATETIME, END_DATETIME, 
        DATETIME, DATETIME, 
        GOOD_START_DATES[0], GOOD_END_DATES[0]);
      TestObject testObject = GetTestObject(xml);

      list.Add(testObject);

      return list;
    }

    public List<TestObject> BAD_MultipleElements()
    {

      List<TestObject> list = new List<TestObject>();
      string xml;
      TestObject testObject;

      // repeat start
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, DATETIME, GOOD_START_DATES[0], GOOD_END_DATES[0],
        true, false, false, false);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // repeat end
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, DATETIME, GOOD_START_DATES[0], GOOD_END_DATES[0],
        false, true, false, false);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // repeat start date
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, DATETIME, GOOD_START_DATES[0], GOOD_END_DATES[0],
        false, false, true, false);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // repeat end date
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, DATETIME, GOOD_START_DATES[0], GOOD_END_DATES[0],
        false, false, false, true);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      return list;
    }

    public List<TestObject> BAD_MissingElements()
    {
      List<TestObject> list = new List<TestObject>();
      string xml;
      TestObject testObject;

      // no elements
      xml = GetXml(DATETIMERANGE_TYPE, null, null, null, null, null, null);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // no start element
      xml = GetXml(DATETIMERANGE_TYPE, null, END_DATETIME, null, DATETIME, null, GOOD_END_DATES[0]);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // no end element
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, null, DATETIME, null, GOOD_START_DATES[0], null);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // no start internal
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, null, DATETIME, null, GOOD_END_DATES[0]);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // no end internal
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, null, GOOD_START_DATES[0], null);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // no start date
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, DATETIME, "", GOOD_END_DATES[0]);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // no end date
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, DATETIME, GOOD_START_DATES[0], "");
      testObject = GetTestObject(xml);
      list.Add(testObject);

      return list;
    }

    public List<TestObject> BAD_BadContent()
    {
      List<TestObject> list = new List<TestObject>();
      string xml;
      TestObject testObject;

      // bad name start
      xml = GetXml(DATETIMERANGE_TYPE, "asdf", END_DATETIME, DATETIME, DATETIME, GOOD_START_DATES[0], GOOD_END_DATES[0]);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // bad name end
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, "asdf", DATETIME, DATETIME, GOOD_START_DATES[0], GOOD_END_DATES[0]);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // bad name start date
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, "asdf", DATETIME, GOOD_START_DATES[0], GOOD_END_DATES[0]);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // bad name end date
      xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, "asdf", GOOD_START_DATES[0], GOOD_END_DATES[0]);
      testObject = GetTestObject(xml);
      list.Add(testObject);

      // bad start date content
      foreach (string content in BAD_DATES)
      {
        xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, DATETIME, content, GOOD_END_DATES[0]);
        testObject = GetTestObject(xml);
        list.Add(testObject);
      }

      // bad end date content
      foreach (string content in BAD_DATES)
      {
        xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, DATETIME, GOOD_START_DATES[0], content);
        testObject = GetTestObject(xml);
        list.Add(testObject);
      }

      // times mismatch
      foreach (string content in BAD_END_DATES)
      {
        xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, DATETIME, GOOD_START_DATES[0], content);
        testObject = GetTestObject(xml);
        list.Add(testObject);
      }

      return list;
    }

    public List<TestObject> GOOD_GoodContent()
    {
      List<TestObject> list = new List<TestObject>();
      string xml;
      TestObject testObject;

      // good content
      foreach (string startDate in GOOD_START_DATES)
      {
        foreach (string endDate in GOOD_END_DATES)
        {
          xml = GetXml(DATETIMERANGE_TYPE, START_DATETIME, END_DATETIME, DATETIME, DATETIME, startDate, endDate);
          testObject = GetTestObject(xml);
          list.Add(testObject);
        }
      }

      return list;
    }

    protected override string GetXml(string xml)
    {
      xml = base.GetXml(xml).Replace(
        INNER_PREFIX_SUB, EDXLSharp.EDXLConstants.NiemCorePrefix).Replace(
        INNER_NAMESPACE_SUB, EDXLSharp.EDXLConstants.NiemCoreNamespace);

      return xml;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="xml">the starting XML</param>
    /// <param name="startElement">the string to use for the start date string. if null, don't include.</param>
    /// <param name="endElement">the string to use for the end date string. if null, don't include.</param>
    /// <param name="startDateElement">the string to use for the date. if null, don't include.</param>
    /// <param name="endDateElement"></param>
    /// <param name="startDate">the start date</param>
    /// <param name="endDate">the end date</param>
    /// <returns></returns>
    private string GetXml(string xml, string startElement, string endElement, string startDateElement,
      string endDateElement, string startDate, string endDate, 
      bool repeatStart = false, bool repeatEnd = false, bool repeatStartDate = false, bool repeatEndDate = false)
    {
      string starDatetXml = "";
      if (startDateElement != null)
      {
        starDatetXml = GetXml(DATETIME_TYPE).Replace(INNER_NAME_SUB, startDateElement).Replace(CONTENT_SUB, startDate);
        if (repeatStartDate)
        {
          starDatetXml += starDatetXml;
        }
      }
      string endDateXml = "";
      if (endDateElement != null)
      {
        endDateXml = GetXml(DATETIME_TYPE).Replace(INNER_NAME_SUB, endDateElement).Replace(CONTENT_SUB, endDate);
        if (repeatEndDate)
        {
          endDateXml += endDateXml;
        }
      }

      string startXml = "";
      if (startElement != null)
      {
        startXml = GetXml(DATETIME_TYPE).Replace(INNER_NAME_SUB, startElement).Replace(CONTENT_SUB, starDatetXml);
        if (repeatStart)
        {
          startXml += startXml;
        }
      }
      string endXml = "";
      if (endElement != null)
      {
        endXml = GetXml(DATETIME_TYPE).Replace(INNER_NAME_SUB, endElement).Replace(CONTENT_SUB, endDateXml);
        if (repeatEnd)
        {
          endXml += endXml;
        }
      }

      string rangeXml = GetXml(xml).Replace(START_DATETIME_SUB, startXml).Replace(END_DATETIME_SUB, endXml);


      return rangeXml;
    }
  }
}
